package com.zw.cloud.mybatis.plus.service.impl.stenter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.common.collect.Lists;
import com.zw.cloud.common.utils.BigDecimalUtils;
import com.zw.cloud.mybatis.plus.entity.stenter.Dictionary;
import com.zw.cloud.mybatis.plus.entity.stenter.OptimizeCraftPageDTO;
import com.zw.cloud.mybatis.plus.entity.stenter.ProductRecordDetail;
import com.zw.cloud.mybatis.plus.enums.OptimizeCraftEnum;
import com.zw.cloud.mybatis.plus.enums.StenterInfluxDBEnum;
import com.zw.cloud.mybatis.plus.event.BaseEvent;
import com.zw.cloud.mybatis.plus.event.EventPublisher;
import com.zw.cloud.mybatis.plus.mapper.stenter.ProductRecordDetailMapper;
import com.zw.cloud.mybatis.plus.service.api.stenter.IProductRecordDetailService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zw.cloud.mybatis.plus.task.stenter.OptimizeCraftTask;
import com.zw.cloud.mybatis.plus.util.TransactionUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 生产记录关联表 服务实现类
 * </p>
 *
 * @author zw
 * @since 2023-10-31
 */
@Service
public class ProductRecordDetailServiceImpl extends ServiceImpl<ProductRecordDetailMapper, ProductRecordDetail> implements IProductRecordDetailService {

    @Autowired
    private EventPublisher eventPublisher;
    @Autowired
    private OptimizeCraftTask optimizeCraftTask;

    @Override
    public boolean insertOrUpdateBatch(List<ProductRecordDetail> detailList) {
        if (CollectionUtils.isEmpty(detailList)) {
            return true;
        }
        List<Long> productRecordIdList = detailList.stream().map(ProductRecordDetail::getProductRecordId).collect(Collectors.toList());
        LambdaQueryWrapper<ProductRecordDetail> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(ProductRecordDetail::getProductRecordId, productRecordIdList);
        List<ProductRecordDetail> productRecordDetailList = baseMapper.selectList(queryWrapper);
        Map<Long, Long> productRecordIdToIdMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(productRecordDetailList)) {
            productRecordIdToIdMap = productRecordDetailList.stream().collect(Collectors.toMap(ProductRecordDetail::getProductRecordId, ProductRecordDetail::getId));
        }
        for (ProductRecordDetail productRecordDetail : detailList) {
            Long id = productRecordIdToIdMap.get(productRecordDetail.getProductRecordId());
            productRecordDetail.setId(id);
        }
        return saveOrUpdateBatch(detailList, detailList.size());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean onDuplicateKeyUpdate(List<ProductRecordDetail> detailList) {
        detailList.forEach(productRecordDetail -> {
            productRecordDetail.setRepairDepartment(Optional.ofNullable(productRecordDetail.getRepairDepartment()).orElse(""));
            productRecordDetail.setRetention(Optional.ofNullable(productRecordDetail.getRetention()).orElse(0));
        });
        boolean success = baseMapper.onDuplicateKeyUpdate(detailList) > 0;
        TransactionUtils.afterCommitSyncExecute(() -> {
            eventPublisher.publish(new BaseEvent<>(1, success));
        });
        //eventPublisher.publish(new BaseEvent<>(1,success,true));
        System.out.println("test");
        return success;
    }

    @Override
    public boolean batchUpdateBaseTenterCraftId(List<Long> idList, Long baseTenterCraftId) {
        LambdaUpdateWrapper<ProductRecordDetail> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(ProductRecordDetail::getBaseTenterCraftId, baseTenterCraftId)
                .in(ProductRecordDetail::getId, idList);
        return baseMapper.update(null, updateWrapper) > 0;
    }

    /**
     * 查询时间范围内 需要计算可优化工艺的数据
     */
    @Override
    public List<Long> queryBaseTenterCraftId(LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.queryBaseTenterCraftId(startTime, endTime);
    }

    @Override
    public List<Long> queryProductInfoIdByBaseTenterCraftId(Long baseTenterCraftId, LocalDateTime startTime, LocalDateTime endTime) {
        return baseMapper.queryProductInfoIdByBaseTenterCraftId(baseTenterCraftId, startTime, endTime);
    }

    /**
     * 查询可优化工艺 相关参数
     */
    @Override
    public List<OptimizeCraftPageDTO> queryOptimizeCraftData(List<Long> productInfoIdList) {
        StringBuilder sqlBuilder = new StringBuilder();
        buildSelectSQL(sqlBuilder, false);
        sqlBuilder.append("a.product_info_id in (");

        productInfoIdList.forEach(id -> sqlBuilder.append(id).append(","));
        sqlBuilder.deleteCharAt(sqlBuilder.length() - 1).append(")");
        StringBuilder orderBy = new StringBuilder(" ORDER BY FIELD(a.product_info_id");
        productInfoIdList.forEach(id -> orderBy.append(",").append(id));
        orderBy.append(")");
        sqlBuilder.append(orderBy);
        List<OptimizeCraftPageDTO> optimizeCraftPageDTOList = baseMapper.queryOptimizeCraftData(sqlBuilder.toString());
        return parseOptimizeCraftPageJson(optimizeCraftPageDTOList);
    }

    /**
     * 根据生产记录ID查询可优化工艺相关参数
     * 根据ID顺序排序
     */
    @Override
    public List<OptimizeCraftPageDTO> queryOptimizeCraftDataByProductRecordId(List<Long> productRecordIdList) {
        StringBuilder sqlBuilder = new StringBuilder();
        buildSelectSQL(sqlBuilder, true);
        sqlBuilder.append(" a.id in (");
        productRecordIdList.forEach(id -> sqlBuilder.append(id).append(","));
        sqlBuilder.deleteCharAt(sqlBuilder.length() - 1).append(")");
        sqlBuilder.append(" ORDER BY FIELD(a.id");
        productRecordIdList.forEach(id -> sqlBuilder.append(",").append(id));
        sqlBuilder.append(")");
        List<OptimizeCraftPageDTO> optimizeCraftPageDTOList = baseMapper.queryOptimizeCraftData(sqlBuilder.toString());
        optimizeCraftPageDTOList = parseOptimizeCraftPageJson(optimizeCraftPageDTOList);
        if (CollectionUtils.isEmpty(optimizeCraftPageDTOList)) {
            return Lists.newArrayList();
        }

        for (OptimizeCraftPageDTO optimizeCraftPageDTO : optimizeCraftPageDTOList) {
            // 温度处理

            Object dryingRoomPresetTemp = optimizeCraftPageDTO.getDryingRoomPresetTemp();
            LinkedHashMap<String, Integer> dryingRoomPresetTempMap = BigDecimalUtils.buildBaseTenterJson(null, dryingRoomPresetTemp, StenterInfluxDBEnum.DRYING_ROOM_ACTUAL_TEMP.getActKey());
            optimizeCraftPageDTO.setDryingRoomPresetTemp(BigDecimalUtils.transferMapKey(dryingRoomPresetTempMap, StenterInfluxDBEnum.DRYING_ROOM_ACTUAL_TEMP.getActKey(), StenterInfluxDBEnum.DRYING_ROOM_ACTUAL_TEMP.getSettingKey()));
            optimizeCraftPageDTO.setDryingRoomTemp(optimizeCraftTask.filterMaxSameValueFromMap(dryingRoomPresetTempMap));

            // 门幅处理
            Object doorWidthActual = optimizeCraftPageDTO.getDoorWidthActual();
            LinkedHashMap<String, Object> doorWidthActualMap = BigDecimalUtils.buildBaseTenterDoorWidthActualJson(null, doorWidthActual, StenterInfluxDBEnum.DOOR_WIDTH_ACTUAL.getActKey());
            optimizeCraftPageDTO.setDoorWidthActual(doorWidthActualMap);

            // 循环风
            Object speciCycleWindSpeed = optimizeCraftPageDTO.getSpeciCycleWindSpeed();
            LinkedHashMap<String, Integer> speciCycleWindSpeedMap = BigDecimalUtils.buildBaseTenterJson(null, speciCycleWindSpeed, StenterInfluxDBEnum.CYCLE_WIND_SPEED.getActKey());
            LinkedHashMap<String, Integer> cycleWindSpeedMap = BigDecimalUtils.transferMapKey(speciCycleWindSpeedMap, StenterInfluxDBEnum.CYCLE_WIND_SPEED.getActKey(), StenterInfluxDBEnum.CYCLE_WIND_SPEED.getSettingKey());

            optimizeCraftPageDTO.setSpeciCycleWindSpeed(cycleWindSpeedMap);
            optimizeCraftPageDTO.setFanSpeed(optimizeCraftTask.filterMaxSameValueFromMap(cycleWindSpeedMap));

            // 循环风上
            LinkedHashMap<String, Integer> circulatingAirMap = optimizeCraftTask.parseCirculatingAirUpperOrLower(cycleWindSpeedMap, 10, true, OptimizeCraftEnum.CIRCULATING_AIR_UPPER.getCraftParamName());
            optimizeCraftPageDTO.setCirculatingAirUpperMap(circulatingAirMap);
            optimizeCraftPageDTO.setCirculatingAirUpper(optimizeCraftTask.filterMaxSameValueFromMap(circulatingAirMap));

            // 循环风下
            LinkedHashMap<String, Integer> circulatingAirLowerMap = optimizeCraftTask.parseCirculatingAirUpperOrLower(cycleWindSpeedMap, 10, false, OptimizeCraftEnum.CIRCULATING_AIR_UPPER.getCraftParamName());
            optimizeCraftPageDTO.setCirculatingAirLowerMap(circulatingAirLowerMap);
            optimizeCraftPageDTO.setCirculatingAirLower(optimizeCraftTask.filterMaxSameValueFromMap(circulatingAirLowerMap));


        }
        return optimizeCraftPageDTOList;
    }

    private void buildSelectSQL(StringBuilder sqlBuilder, boolean needAssistant) {
        sqlBuilder.append("SELECT a.id as productRecordId,a.product_card_code,a.end_time,c.speed,\n" +
                "c.drying_room_actual_temp as dryingRoomPresetTemp,c.cycle_wind_speed as speciCycleWindSpeed,c.total_amplitude,c.door_width_actual, c.top_feed,c.lower_feed,c.brush_feed,a.upper_door_width,a.lower_door_width as landingDoorWidth,b.reduction_amplitude,b.washing_rear_door_width,a.pre_weight as schedulePreWeight,a.gram_heft as scheduleGramHeft,\n" +
                "b.reduction_weight,b.weight_after_washing,b.lon,b.lat,b.craft_shrinkage,b.upper_weft_density as upperScheduleWeftDensity,b.upper_warp_density,a.weft_density as scheduleWeftDensity,b.lower_warp_density ");
        if (needAssistant) {
            sqlBuilder.append(",a.assistant ");
        }
        sqlBuilder.append("FROM `product_record` as a\n" +
                "INNER JOIN history_product_info_carft as c\n" +
                "on a.product_info_id = c.product_info_id\n" +
                "LEFT JOIN product_record_detail as b\n" +
                "on a.id = b.product_record_id\n" +
                "where ");
    }

    private LinkedHashMap<String, Object> parseJson(Object o) {
        if (Objects.isNull(o)) {
            return null;
        }
        return JSON.parseObject(o.toString(), new TypeReference<LinkedHashMap<String, Object>>() {
        });
    }

    private List<OptimizeCraftPageDTO> parseOptimizeCraftPageJson(List<OptimizeCraftPageDTO> optimizeCraftPageDTOList) {
        if (CollectionUtils.isEmpty(optimizeCraftPageDTOList)) {
            return Lists.newArrayList();
        }
        optimizeCraftPageDTOList.forEach(optimizeCraftPageDTO -> {
            optimizeCraftPageDTO.setDryingRoomPresetTemp(parseJson(optimizeCraftPageDTO.getDryingRoomPresetTemp()));
            optimizeCraftPageDTO.setDoorWidthActual(parseJson(optimizeCraftPageDTO.getDoorWidthActual()));
            optimizeCraftPageDTO.setSpeciCycleWindSpeed(parseJson(optimizeCraftPageDTO.getSpeciCycleWindSpeed()));
            Object assistant = optimizeCraftPageDTO.getAssistant();
            if (Objects.nonNull(assistant)) {
                optimizeCraftPageDTO.setAssistant(JSON.parseArray(assistant.toString(), Dictionary.class));
            }
        });
        return optimizeCraftPageDTOList;
    }
}
